package top.lywivan.netty.reactor.cnxn;


import top.lywivan.netty.reactor.Server;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicLong;

public abstract class ServerCnxn {


    public static final int maxBuffer = Integer.getInteger("maxbuffer", 0xfffff);

    final Server server;

    public ServerCnxn(Server server) {
        this.server = server;
    }


    public abstract void sendBuffer(ByteBuffer... buffers);

    public void requestInterestOpsUpdate(){

    }

    public abstract int getInterestOps();

    abstract void enableRecv();

    void disableRecv() {
        disableRecv(true);
    }

    abstract void disableRecv(boolean waitDisableRecv);


    AtomicLong outstandingCount = new AtomicLong();

    // 请求进来时检查是否需要限流 , 然后 disable read
    public void incrOutstandingAndCheckThrottle() {
        if (server.shouldThrottle(outstandingCount.incrementAndGet())) {
            disableRecv(false);
        }
    }

    // 请求结束时检查是否结束限流, 不继续限流则 enable read
    public void decrOutstandingAndCheckThrottle() {
        if (!server.shouldThrottle(outstandingCount.decrementAndGet())) {
            enableRecv();
        }
    }


    public enum DisconnectReason {
        UNKNOWN("unknown"),
        SERVER_SHUTDOWN("server_shutdown"),
        CLOSE_ALL_CONNECTIONS_FORCED("close_all_connections_forced"),
        CONNECTION_CLOSE_FORCED("connection_close_forced"),
        CONNECTION_EXPIRED("connection_expired"),
        CLIENT_CLOSED_CONNECTION("client_closed_connection"),
        CLIENT_CLOSED_SESSION("client_closed_session"),
        UNABLE_TO_READ_FROM_CLIENT("unable_to_read_from_client"),
        NOT_READ_ONLY_CLIENT("not_read_only_client"),
        CLIENT_ZXID_AHEAD("client_zxid_ahead"),
        INFO_PROBE("info_probe"),
        CLIENT_RECONNECT("client_reconnect"),
        CANCELLED_KEY_EXCEPTION("cancelled_key_exception"),
        IO_EXCEPTION("io_exception"),
        IO_EXCEPTION_IN_SESSION_INIT("io_exception_in_session_init"),
        BUFFER_UNDERFLOW_EXCEPTION("buffer_underflow_exception"),
        SASL_AUTH_FAILURE("sasl_auth_failure"),
        RESET_COMMAND("reset_command"),
        CLOSE_CONNECTION_COMMAND("close_connection_command"),
        CLEAN_UP("clean_up"),
        CONNECTION_MODE_CHANGED("connection_mode_changed"),
        RENEW_GLOBAL_SESSION_IN_RO_MODE("renew a global session in readonly mode"),
        // Below reasons are NettyServerCnxnFactory only
        CHANNEL_DISCONNECTED("channel disconnected"),
        CHANNEL_CLOSED_EXCEPTION("channel_closed_exception"),
        AUTH_PROVIDER_NOT_FOUND("auth provider not found"),
        FAILED_HANDSHAKE("Unsuccessful handshake"),
        CLIENT_RATE_LIMIT("Client hits rate limiting threshold"),
        CLIENT_CNX_LIMIT("Client hits connection limiting threshold");

        String disconnectReason;

        DisconnectReason(String reason) {
            this.disconnectReason = reason;
        }

        public String toDisconnectReasonString() {
            return disconnectReason;
        }
    }


    protected static class EndOfStreamException extends IOException {

        private static final long serialVersionUID = -8255690282104294178L;

        private DisconnectReason reason;

        public EndOfStreamException(String msg, DisconnectReason reason) {
            super(msg);
            this.reason = reason;
        }

        public String toString() {
            return "EndOfStreamException: " + getMessage();
        }
        public DisconnectReason getReason() {
            return reason;
        }

    }
}
